

#include "instruction.h"
#include "limits.h"

#include <kernel/handle/handle.h>

#define MAXOPCODE 0	/* should be the number of instructions */


#define R(A) (_state->Registers [A])
#define K(B) (_state->Agent->DataSegment [B])
#define S(B) (_state->Agent->TextSegment + B)
#define RK(B) (B < VM_REGS_SIZE ? R (B) : K (B - VM_REGS_SIZE))
#define IP (_state->InstructionPointer)
#define SKIP IP += 1


static void cb_mov (vm_State *_state, int A, int B, int C)
{
	R (A).Integer = RK (B).Integer;
}

static void cb_movf (vm_State *_state, int A, int B, int C)
{
	R (A).Float = RK (B).Float;
}

static void cb_add (vm_State *_state, int A, int B, int C)
{
	R (A).Integer = RK (B).Integer + RK (C).Integer;
}


static void cb_addf (vm_State *_state, int A, int B, int C)
{
	R (A).Float = RK (B).Float + RK (C).Float;
}


static void cb_sub (vm_State *_state, int A, int B, int C)
{
	R (A).Integer = RK (B).Integer - RK (C).Integer;
}


static void cb_subf (vm_State *_state, int A, int B, int C)
{
	R (A).Float = RK (B).Float - RK (C).Float;
}


static void cb_mul (vm_State *_state, int A, int B, int C)
{
	R (A).Integer = RK (B).Integer * RK (C).Integer;
}


static void cb_mulf (vm_State *_state, int A, int B, int C)
{
	R (A).Float = RK (B).Float * RK (C).Float;
}


static void cb_div (vm_State *_state, int A, int B, int C)
{
	R (A).Integer = RK (B).Integer / RK (C).Integer;
}


static void cb_divf (vm_State *_state, int A, int B, int C)
{
	R (A).Float = RK (B).Float / RK (C).Float;
}


static void cb_mod (vm_State *_state, int A, int B, int C)
{
	R (A).Integer = RK (B).Integer % RK (C).Integer;
}


static void cb_land (vm_State *_state, int A, int B, int C)
{
	R (A).Integer = RK (B).Integer && RK (C).Integer;
}


static void cb_lor (vm_State *_state, int A, int B, int C)
{
	R (A).Integer = RK (B).Integer || RK (C).Integer;
}


static void cb_and (vm_State *_state, int A, int B, int C)
{
	R (A).Integer = RK (B).Integer & RK (C).Integer;
}


static void cb_or (vm_State *_state, int A, int B, int C)
{
	R (A).Integer = RK (B).Integer | RK (C).Integer;
}


static void cb_xor (vm_State *_state, int A, int B, int C)
{
	R (A).Integer = RK (B).Integer ^ RK (C).Integer;
}


static void cb_cmp (vm_State *_state, int A, int B, int C)
{
	R (A).Integer = ~ RK (B).Integer;
}


static void cb_shl (vm_State *_state, int A, int B, int C)
{
	R (A).Integer = RK (B).Integer << RK (C).Integer;
}


static void cb_shr (vm_State *_state, int A, int B, int C)
{
	R (A).Integer = RK (B).Integer >> RK (C).Integer;
}


static void cb_jump (vm_State *_state, int A, int Bx)
{
	IP += Bx;
}


static void cb_eq (vm_State *_state, int A, int B, int C)
{
	if ((RK (B).Integer == RK (C).Integer) != A) SKIP;
}


static void cb_eqf (vm_State *_state, int A, int B, int C)
{
	if ((RK (B).Float == RK (C).Float) != A) SKIP;
}


static void cb_lt (vm_State *_state, int A, int B, int C)
{
	if ((RK (B).Integer < RK (C).Integer) != A) SKIP;
}


static void cb_ltf (vm_State *_state, int A, int B, int C)
{
	if ((RK (B).Float < RK (C).Float) != A) SKIP;
}


static void cb_le (vm_State *_state, int A, int B, int C)
{
	if ((RK (B).Integer <= RK (C).Integer) != A) SKIP;
}


static void cb_lef (vm_State *_state, int A, int B, int C)
{
	if ((RK (B).Float <= RK (C).Float) != A) SKIP;
}


static void cb_for (vm_State *_state, int A, int Bx)
{
	R (A).Integer += R (A + 2).Integer;

	if (R (A).Integer <= R (A + 1).Integer) IP += Bx;
}


static void cb_forf (vm_State *_state, int A, int Bx)
{
	R (A).Float += R (A + 2).Float;

	if (R (A).Float <= R (A + 1).Float) IP += Bx;
}


static void cb_req (vm_State *_state, int A, int Bx)
{
	R (A).Integer = handle_request (S (Bx), _state->Agent->ID);
}


static void cb_rel (vm_State *_state, int A, int Bx)
{
	handle_release (R (A).Integer);
}


static void cb_recv (vm_State *_state, int A, int B, int C)
{
	handle_read (_state->Caller, (char *) &R (A).Integer, sizeof (vm_Integer));
}


static void cb_recvf (vm_State *_state, int A, int B, int C)
{
	handle_read (_state->Caller, (char *) &R (A).Float, sizeof (vm_Float));
}


static void cb_ret (vm_State *_state, int A, int B, int C)
{
	handle_write (_state->Caller, (char *) &R (A).Integer, sizeof (vm_Integer));
}


static void cb_retf (vm_State *_state, int A, int B, int C)
{
	handle_write (_state->Caller, (char *) &R (A).Float, sizeof (vm_Float));
}


static void cb_send (vm_State *_state, int A, int B, int C)
{
	handle_write (R (A).Handle, (char *) &RK (B).Integer, sizeof (vm_Integer));
}


static void cb_sendf (vm_State *_state, int A, int B, int C)
{
	handle_write (R (A).Handle, (char *) &RK (B).Float, sizeof (vm_Float));
}


static void cb_wrt (vm_State *_state, int A, int Bx)
{
	handle_writestring (R (A).Handle, S (Bx));
}


static void cb_call (vm_State *_state, int A, int Bx)
{
	R (A).Handle = vm_call (_state->Agent.Header.AgentName, S (Bx));
}


static vm_Instruction InstructionTable [] = {
	{"mov", VM_INSTRUCTION_ABC, (vm_Callback) cb_mov},
	{"movf", VM_INSTRUCTION_ABC, (vm_Callback) cb_movf},
	{"add", VM_INSTRUCTION_ABC, (vm_Callback) cb_add},
	{"addf", VM_INSTRUCTION_ABC, (vm_Callback) cb_addf},
	{"sub", VM_INSTRUCTION_ABC, (vm_Callback) cb_sub},
	{"subf", VM_INSTRUCTION_ABC, (vm_Callback) cb_subf},
	{"mul", VM_INSTRUCTION_ABC, (vm_Callback) cb_mul},
	{"mulf", VM_INSTRUCTION_ABC, (vm_Callback) cb_mulf},
	{"div", VM_INSTRUCTION_ABC, (vm_Callback) cb_div},
	{"divf", VM_INSTRUCTION_ABC, (vm_Callback) cb_divf},
	{"mod", VM_INSTRUCTION_ABC, (vm_Callback) cb_mod},
	{"land", VM_INSTRUCTION_ABC, (vm_Callback) cb_land},
	{"lor", VM_INSTRUCTION_ABC, (vm_Callback) cb_lor},
	{"and", VM_INSTRUCTION_ABC, (vm_Callback) cb_and},
	{"or", VM_INSTRUCTION_ABC, (vm_Callback) cb_or},
	{"xor", VM_INSTRUCTION_ABC, (vm_Callback) cb_xor},
	{"cmp", VM_INSTRUCTION_ABC, (vm_Callback) cb_cmp},
	{"shl", VM_INSTRUCTION_ABC, (vm_Callback) cb_shl},
	{"shr", VM_INSTRUCTION_ABC, (vm_Callback) cb_shr},
	{"jump", VM_INSTRUCTION_ABx, (vm_Callback) cb_jump},
	{"eq", VM_INSTRUCTION_ABC, (vm_Callback) cb_eq},
	{"eqf", VM_INSTRUCTION_ABC, (vm_Callback) cb_eqf},
	{"lt", VM_INSTRUCTION_ABC, (vm_Callback) cb_lt},
	{"ltf", VM_INSTRUCTION_ABC, (vm_Callback) cb_ltf},
	{"le", VM_INSTRUCTION_ABC, (vm_Callback) cb_le},
	{"lef", VM_INSTRUCTION_ABC, (vm_Callback) cb_lef},
	{"for", VM_INSTRUCTION_ABx, (vm_Callback) cb_for},
	{"forf", VM_INSTRUCTION_ABx, (vm_Callback) cb_forf},
	{"req", VM_INSTRUCTION_ABx, (vm_Callback) cb_req},
	{"rel", VM_INSTRUCTION_ABx, (vm_Callback) cb_rel},
	{"recv", VM_INSTRUCTION_ABC, (vm_Callback) cb_recv},
	{"recvf", VM_INSTRUCTION_ABC, (vm_Callback) cb_recvf},
	{"ret", VM_INSTRUCTION_ABC, (vm_Callback) cb_ret},
	{"retf", VM_INSTRUCTION_ABC, (vm_Callback) cb_retf},
	{"send", VM_INSTRUCTION_ABC, (vm_Callback) cb_send},
	{"sendf", VM_INSTRUCTION_ABC, (vm_Callback) cb_sendf},
	{"wrt", VM_INSTRUCTION_ABx, (vm_Callback) cb_wrt},
	{"call", VM_INSTRUCTION_ABC, (vm_Callback) cb_call},
	{NULL, 0, NULL}
};


vm_Instruction *vm_instruction_mnemonic (const char *_mnemonic)
{
	index i;

	for (i = 0; InstructionTable [i].Mnemonic != NULL; ++i)
	{
		if (stringequal (_mnemonic, InstructionTable [i].Mnemonic))
		{
			return &InstructionTable [i];
		}
	}

	return NULL;
}


vm_Instruction *vm_instruction_opcode (char _opcode)
{
	if (_opcode > MAXOPCODE)
	{
		return NULL;
	}

	return &InstructionTable [_opcode];
}



